
import Foundation
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct PropDelegate: AccessorMacro {
    public static func expansion(
        of node: SwiftSyntax.AttributeSyntax, providingAccessorsOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext
    ) throws -> [SwiftSyntax.AccessorDeclSyntax] {

        guard let varName = declaration.variableName,
            let typeInfo = declaration.variableType
        else { fatalError("NO variable name found") }

        let target: String? = node.argument(label: "target")
        if(target == nil) { fatalError("No target") } 

        var missValue: String? = node.argument(label: "miss")
        if missValue == "nil" {
            missValue = nil
        }

        var propKey = varName.quoted
        if let keyName = node.argument(label: "key") {
            if !keyName.isEmpty && keyName != "nil" {
                propKey = keyName.trimmingCharacters(in: .whitespaces)
            }
        }

        var asBuf = ""
        if typeInfo.optional {
            asBuf = "as? " + typeInfo.name
        } else {
            asBuf = "as! " + typeInfo.name
        }

        let getter: String

        if missValue == nil {
            getter = """
                get{
                    \(target!).getProperty(obj: self, key: \(propKey)) \(asBuf)
                }
                """
        } else {
            getter = """
                get{
                    \(target!).getProperty(obj: self, key: \(propKey)) as? \(typeInfo.name) ?? \(missValue!)
                }
                """
        }

        let setter = """
            set(newValue){
                \(target!).setProperty(obj: self, key: \(propKey), value: newValue)
            }
            """
        let spec = declaration.variableSpecifier
        if spec == "var" {
            return [AccessorDeclSyntax(stringLiteral: getter), AccessorDeclSyntax(stringLiteral: setter)]
        }
        fatalError("Only 'var' is support.")
    }

}
